#__Author__  = white
import socketserver,json,os
import socket,selectors
class FtpServer(object):
    def __init__(self,sock):
        self.upload_dict={}
        self.sock = sock
        self.sel = selectors.DefaultSelector()

    def start(self):

        self.sock.listen(100)
        self.sock.setblocking(False)
        self.sel.register(sock, selectors.EVENT_READ, self.accept)
        while True:
            events = self.sel.select()
            for key, mask in events:
                callback = key.data
                callback(key.fileobj)
    def accept(self,sock):
        conn, addr = sock.accept()
        print('accepted', conn, 'from', addr)
        conn.setblocking(False)
        self.sel.register(conn, selectors.EVENT_READ, self.read)

    def read(self,conn):
        data = conn.recv(1024)
        if data:
            cmd_dic = eval(data.decode('utf-8'))
            action = cmd_dic['action']
            filename = cmd_dic['filename']
            fileaddr = cmd_dic['fileaddr']

            if action == 'put':
                cmd_dic["recv_size"] = 0

                file = fileaddr + '/' + filename
                if os.path.isfile(file):
                    f = open(file + ".new", 'wb')
                    cmd_dic['wfd'] = f
                else:
                    f = open(file, 'wb')
                    cmd_dic['wfd'] = f
                self.upload_dict[conn] = cmd_dic
                conn.send(b'200ok')
                self.sel.modify(conn, selectors.EVENT_READ, self.put)
        else:
            print('closing', conn)
            self.sel.unregister(conn)
            conn.close()
    def ls(self,conn,*args):
        cmd_dic = args[0]
        fileaddr = cmd_dic["fileaddr"]
        ls_results = os.popen("ls %s"%fileaddr).read()
        print(ls_results)
        if ls_results == "":
            conn.send("当前目录为空".encode())
        else:
            conn.send(ls_results.encode())

    def put(self,conn,*args):
        filename = self.upload_dict[conn]["filename"] #对应client文件名简称
        filesize = self.upload_dict[conn]["filesize"]
        fileaddr = self.upload_dict[conn]["fileaddr"]
        f = self.upload_dict[conn]["wfd"]
        #print(self.upload_dict['fileaddr'])
        #file = fileaddr + '/'+filename
        # if os.path.isfile(file):
        #     f = open(file+".new",'wb')
        # else:
        #     f = open(file,'wb')
        #     self.upload_dict['wfd'] = f
        #conn.send(b"200 ok")
        # self.upload_dict["recv_size"] = 0

        recv_size = self.upload_dict[conn]["recv_size"]
        while recv_size < filesize:
            if int(filesize) - int(recv_size) >=1024:
                size = 1024
            else:
                size = int(filesize) - int(recv_size)
            try:
                recv_data = conn.recv(size)
                f.write(recv_data)
                recv_size += len(recv_data)
                self.upload_dict[conn]['recv_size'] = recv_size
                if filesize == recv_size:
                    f.close()
                    print("传输完毕")
                    self.sel.modify(conn, selectors.EVENT_READ, self.read)
            except BlockingIOError:
                break
        else:
            print("file %s put over"%filename)
        print('退出')
    def pwd(self,conn,*args):
        send_data = os.popen("pwd").read()
        print(send_data)
        conn.send(send_data.encode())
    def cd(self,conn,*args):
        cmd_dic = args[0]
        addr = cmd_dic["addr"]
        cd_result = os.path.isdir(addr)
        if cd_result:
            msg = {
                "cd_result":"success",
                "catalog":addr
            }

            conn.send(json.dumps(msg).encode())
        else:
            msg = {
            "cd_result": "error",

            }
            conn.send(json.dumps(msg).encode())
    # def handle(self,conn):
    #     data = conn.recv(1024)
    #     if data:
    #         print('data:',data.decode('utf-8'),'end!!!!!')
    #         cmd_dic = eval(data.decode('utf-8'))
    #         print(cmd_dic)
    #         action = cmd_dic["action"]
    #         if hasattr(self,action):
    #             func = getattr(self,action)
    #             #func(conn,cmd_dic)
    #             self.sel.modify(conn, selectors.EVENT_READ, self.put)
    #     else:
    #         print('closing', conn)
    #         self.sel.unregister(conn)
    #         conn.close()


if __name__ == "__main__":
    sock = socket.socket()
    sock.bind(('0.0.0.0', 10003))
    s = FtpServer(sock)
    s.start()


